<?php

class Application_View_Helper_Table extends Zend_View_Helper_Abstract {

    public function table($rows, $defs, $options = array()) {
        if ($rows instanceof Zend_Db_Select) {
            $rows = $rows->query()->fetchAll();
        }
//        $this->view->headLink()->appendStylesheet($this->view->baseUrl() . '/css/table.css');
        $options = $this->createOptions($options);
        $tableDescriptor = $this->createTableDescriptor($defs, $options);
        if ($options['emptyTextEnable'] && (!$rows || count($rows) == 0)) {
            return $this->renderTableNoData($tableDescriptor, $options);
        }
        $parsedRows = $this->createRealRows($rows, $tableDescriptor, $options);
        return $this->view->partial($options['viewPath'], array(
                    'rows' => $rows, 'descriptor' => $tableDescriptor,
                    'options' => $options, 'parsedRows' => $parsedRows,
                ));
    }

    public function createRealRows($rows, $tableDescriptor, $options) {
        $result = array();

        foreach ($rows as $row) {
            $replacement = $this->createReplacement($row);
            $r = array();
            foreach ($tableDescriptor as $key => $value) {
                $body = $value['body'];
                $replacement2 = $replacement;
                if ($body['escape']) {
                    foreach ($replacement as $k => $v) {
                        $v = $this->recursiveEscape($v);
                        $replacement2[$k] = $v;
                    }
                }
                $body['rowClass'] = $this->parseExpressions($replacement2, $options['rowClass'], $row);
                $body = $this->parseExpressions($replacement2, $body, $row);
                if (isset($options['url']) && $options['url']) {
                    $body['url'] = $this->parseExpressions($replacement2, $options['url'], $row);
                }
                $r[] = $body;
            }
            $result[] = $r;
        }
        return $result;
    }

    protected function createReplacement($row) {
        $replacement = array();
        foreach ($row as $r => $v) {
            $basePath = array(
                '${item',
                '%24%7Bitem',
            );
            $tmp = $this->createReplacementRecursive($basePath, $r, $v);
            $replacement = array_merge($replacement, $tmp);
        }
        return $replacement;
    }

    protected function createReplacementRecursive(array $basePath, $key, $value) {
        $result = array();
        if (is_array($value)) {
            foreach ($value as $k => $v) {
                $path = array(
                    $basePath[0] . '.' . $key,
                    $basePath[1] . '.' . $key,
                );
                $tmp = $this->createReplacementRecursive($path, $k, $v);
                $result = array_merge($result, $tmp);
            }
        } else {
            $result[$basePath[0] . '.' . $key . '}'] = $value;
            $result[$basePath[1] . '.' . $key . '%7D'] = $value; // gdy bedzie sparsowany jako url
        }

        return $result;
    }

    protected function recursiveEscape($val) {
        if (is_array($val)) {
            $res = array();
            foreach ($val as $k => $v) {
                $res[$k] = $this->recursiveEscape($v);
            }
            return $res;
        }
        return $this->view->escape($val);
    }

    protected function parseExpressions($replacement, $base, $row) {
        if (is_array($base)) {
            if (count($base) == 1 && isset($base['eval'])) {
                $s = $this->recursiveReplace($replacement, $base, $row, true);
                return $s;
            }
            foreach ($base as $k => $v) {
                $base[$k] = $this->parseExpressions($replacement, $v, $row);
            }
            return $base;
        } else {
            return $this->recursiveReplace($replacement, $base, $row);
        }
    }

    protected function recursiveReplace($replacement, $base, $row, $eval = false) {
        if ($eval && count($base) == 1 && isset($base['eval'])) {
            $view = $this->view;
            $result = str_replace(array_keys($replacement), array_values($replacement), $base['eval']);
            eval('$result = ' . $result . ';');
            return $result;
        }
        if (is_array($base)) {
            foreach ($base as $k => $v) {
                $base[$k] = $this->recursiveReplace($replacement, $v, $row);
            }
            return $base;
        }
        $str = str_replace(array_keys($replacement), array_values($replacement), $base);
        return $str;
    }

    protected function getHeader($value) {
        $result = array(
            'label' => '',
            'sortable' => false,
            'filter' => false,
            'class' => '',
            'attributes' => array(),
        );
        if (is_array($value)) {
            $result = array_merge($result, $value);
        } else {
            $result['label'] = $value;
        }
        return $result;
    }

    protected function getBody($value) {
        $result = array(
            'value' => '', // expression
            'class' => '',
            'urlEnable' => true,
            'url' => null,
            'attributes' => array(),
            'escape' => true,
            'rowClass' => '',
        );
        if (is_array($value)) {
            if (isset($value[0])) {
                $result['value'] = $value[0];
                unset($value[0]);
                $result = array_merge($result, $value);
            } elseif (isset($value['value'])) {
                $result = array_merge($result, $value);
                $v = $value['value'];
                if (is_array($v)) {
                    if (isset($v['eval'])) {
                        $result['value'] = $v;
                    } else {
                        $result['value'] = $v[0];
                    }
                } else {
                    $result['value'] = '${item.' . $v . '}';
                }
            } elseif (isset($value['eval'])) {
                $result = array_merge($result, $value);
                $result['value'] = array('eval' => $value['eval']);
            }
        } else {
            $result['value'] = '${item.' . $value . '}';
        }
        return $result;
    }

    public function createTableDescriptor($columnDefinitions, $options) {
        $result = array();
        foreach ($columnDefinitions as $key => $value) {
            $header = array();
            $body = array();
            if (is_string($key)) {
                $header = $this->getHeader($key);
                $body = $this->getBody($value);
            } elseif (is_array($value)) {
                if (isset($value['header'])) {
                    $header = $this->getHeader($value['header']);
                }
                if (isset($value['body'])) {
                    $body = $this->getBody($value['body']);
                }
            }
            $def = array(
                'header' => $header,
                'body' => $body,
            );
            $result[] = $def;
        }

        return $result;
    }

    protected function renderTableNoData($tableDescriptor, $options) {
        return '<div class="data_table no_data">' . $options['emptyText'] . '</div>';
    }

    public function createOptions($options) {
        $defaultOptions = array(
            'emptyTextEnable' => true,
            'emptyText' => 'Brak danych do wyświetlenia',
            'url' => false,
            'viewPath' => 'common/table-default.phtml',
            'rowClass' => '',
            'tableClass' => '',
        );

        $result = array_merge($defaultOptions, $options);
        return $result;
    }

}